package springinpractice.ch4.r4_4.web;

import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;

import net.tanesha.recaptcha.ReCaptcha;
import net.tanesha.recaptcha.ReCaptchaResponse;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.Validator;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import springinpractice.ch4.r4_4.model.User;

/*
 * Author       :       Willie Wheeler and John Wheeler
 * Book         :       'Spring In Practice' [Book written by Willie Wheeler and John Wheeler]
 */

@Controller
@RequestMapping("/register/form")
public class RegFormController {
	private static final String MA_USER = "user";
	private static final String MA_RECAPTCHA_HTML = "reCaptchaHtml";
	
	private Validator validator;
	private ReCaptcha reCaptcha;
	
	@Autowired
	public void setValidator(Validator validator) {
		this.validator = validator;
	}
	
	@Autowired
	public void setReCaptcha(ReCaptcha reCaptcha) {
		this.reCaptcha = reCaptcha;
	}
	
	@RequestMapping(method = RequestMethod.GET)
	public void form(Model model) {
		Logger.global.info("Serving initial form");
		model.addAttribute(MA_USER, new User());
		String html = reCaptcha.createRecaptchaHtml(null, null);
		model.addAttribute(MA_RECAPTCHA_HTML, html);
	}
	
	@RequestMapping(method = RequestMethod.POST)
	public String form(
			HttpServletRequest req,
			@RequestParam("recaptcha_challenge_field") String challenge,
			@RequestParam("recaptcha_response_field") String response,
			@ModelAttribute(MA_USER) User user,
			BindingResult result,
			Model model) {
		
		Logger.global.info("Processing form submission");
		Logger.global.info("challenge=" + challenge + ", response=" + response);
		
		verifyBinding(result);
		validator.validate(user, result);
		
		ReCaptchaResponse reCaptchaResponse =
			reCaptcha.checkAnswer(req.getRemoteAddr(), challenge, response);
		
		if (!reCaptchaResponse.isValid()) {
			result.rejectValue("captcha", "errors.badCaptcha");
		}
		
		String html = reCaptcha.createRecaptchaHtml(null, null);
		model.addAttribute(MA_RECAPTCHA_HTML, html);
		
		if (result.hasErrors()) {
			result.reject("form.problems");
			return "register/form";
		}
		
		Logger.global.info("Processing user: " + user);
		return "redirect:confirm";
	}
	
	@InitBinder
	public void initBinder(WebDataBinder binder) {
		Logger.global.info("Initializing binder");
		binder.setAllowedFields(new String[] { 
			"firstName", "lastName", "email",
			"username", "password", "passwordConfirmation",
			"marketingOk", "acceptTerms",
			"recaptcha_challenge_field", "recaptcha_response_field"
		});
	}
		
	private void verifyBinding(BindingResult result) {
		String[] suppressedFields = result.getSuppressedFields();
		if (suppressedFields.length > 0) {
			throw new RuntimeException("You've attempted to bind fields that haven't been allowed in initBinder(): " 
					+ StringUtils.join(suppressedFields, ", "));
		}
	}	
}
